package controllers

import (
	"math/rand"
	//"errors"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	//"regexp"
	"time"
	//"golang.org/x/net/html"
	"priceApi/models"

	"strconv"
	"strings"

	"github.com/astaxie/beego"
	"golang.org/x/net/proxy"

	"priceApi/utils"

	goquery "github.com/PuerkitoBio/goquery"
	"github.com/astaxie/beego/orm"
	"github.com/robfig/cron"
)

type Proxy struct {
	Ip string `json:"ip"`
	Id string `json:"id"`
}

func GetProxy() (proxy Proxy, err error) {
	url := "http://ip.wenongtang.com/getip/"

	resp, err := http.Get(url)
	if err != nil {
		fmt.Println(err)
		beego.Debug("GetProxy", err.Error())
		return

	}
	defer resp.Body.Close()
	input, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
	}
	//fmt.Println(string(input))
	json.Unmarshal([]byte(input), &proxy)

	return
}

// http get by proxy
func GetByProxy(url_addr string) (*http.Response, int) {
	var user_agent = []string{
		"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
		"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
		"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
		"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
		"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
		"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
		"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
		"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
		"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
		"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
		"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
		"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
		"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
		"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
		"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
		"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
		"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
		"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
	}

	count := 0
	var resp *http.Response
	var err1 error
	for {
		count++
		if count > 5 {
			return resp, count
		}
		ip, _ := GetProxy()
		request, _ := http.NewRequest("GET", url_addr, nil)
		proxy, _ := url.Parse("https://" + ip.Ip)
		request.Header.Add("User-Agent", user_agent[rand.Intn(17)])

		client := &http.Client{
			Transport: &http.Transport{
				Proxy: http.ProxyURL(proxy),
			},
			Timeout: time.Duration(time.Second * 5),
		}

		resp, err1 = client.Do(request)
		if err1 != nil {
			beego.Debug("count:" + strconv.Itoa(count) + "\t" + url_addr + err1.Error())
		}

		//		fmt.Println(resp)
		//		code := resp.StatusCode
		//		if code == 200 {
		//			return resp
		//		} else {
		//			http.Get("http://ip.wenongtang.com/setip/" + ip.Id)
		//		}
		//		time.Sleep(time.Second * 2)

		if resp != nil {
			//fmt.Println(resp.StatusCode)
			if resp.StatusCode == 200 {
				return resp, count
			} else {
				http.Get("http://ip.wenongtang.com/setip/" + ip.Id)
			}
			//time.Sleep(time.Second * 2)
		} else {

			http.Get("http://ip.wenongtang.com/setip/" + ip.Id)
			//time.Sleep(time.Second * 2)
		}
	}

}

func GetBySS(url string) (*http.Response, error) {

	var resp *http.Response

	dialSocksProxy, err := proxy.SOCKS5("tcp", "127.0.0.1:10086", nil, proxy.Direct)
	if err != nil {
		fmt.Println("Error connecting to proxy:", err)
		return resp, err
	}
	//fmt.Println(dialSocksProxy, err)

	tr := &http.Transport{Dial: dialSocksProxy.Dial}
	// Create client
	myClient := &http.Client{
		Transport: tr,
	}

	return myClient.Get(url)

}

type Huobi struct {
	TradeCount float64 `json:"tradeMonthTimes"`
	Price      float64 `json:"price"`
}
type HbOutPrice struct {
	Data []Huobi `json:"data"`
}

func HandleHuobiOutPrice(Symbol, Type string) float64 {
	var hb HbOutPrice
	url := "https://api-otc.huobi.pro/v1/otc/trade/list/public?coinId=" + Symbol + "&tradeType=" + Type + "&currentPage=1&payWay=&country=&merchant=1&online=1&range=0"
	resp, err := GetBySS(url)

	if err != nil {
		return 0
	}
	input, _ := ioutil.ReadAll(resp.Body)
	//fmt.Println(string(input))
	json.Unmarshal([]byte(input), &hb)
	sum := (hb.Data[0].Price*hb.Data[0].TradeCount + hb.Data[1].Price*hb.Data[1].TradeCount + hb.Data[2].Price*hb.Data[2].TradeCount) / (hb.Data[0].TradeCount + hb.Data[1].TradeCount + hb.Data[2].TradeCount)

	return MyRound(sum)
}

func GetHuoOutPrice() {
	symbols := map[string]string{
		"3": "ETH",
		"1": "BTC",
	}

	var BTCbuysell BuySell
	var LTCbuysell BuySell

	for key, value := range symbols {
		var buysell BuySell
		buysell.Buy = HandleHuobiOutPrice(key, "1")
		time.Sleep(time.Second * 2)
		buysell.Sell = HandleHuobiOutPrice(key, "0")
		if key == "1" {
			BTCbuysell = buysell
		}
		SaveData(1, value, buysell)
		//fmt.Println(buysell, value)
	}

	//火币LTC
	//rate := GetRateUSDT()
	LTCbuy, LTCsell := GetHuobidata("LTC")
	//fmt.Println(LTCbuy, LTCsell)
	time.Sleep(time.Second * 4)
	BTCbuy, BTCsell := GetHuobidata("BTC")
	//fmt.Println(BTCbuy, BTCsell)

	LTCbuysell.Buy = MyRound((LTCbuy * BTCbuysell.Buy) / BTCbuy)
	//fmt.Println((LTCbuy * BTCbuysell.Buy) / BTCbuy)
	LTCbuysell.Sell = MyRound((LTCsell * BTCbuysell.Sell) / BTCsell)
	SaveData(1, "LTC", LTCbuysell)

}

func SaveRate(rate float64) {

	if rate > 0 {
		o := orm.NewOrm()
		rate0 := new(models.Rate)
		rate0.Rate = rate
		rate0.Created = int(time.Now().Unix())
		o.Insert(rate0)
	}

}

func GetGateioUSDT() {
	var rate float64
	type JsonData_3 struct {
		Buy  string `json:"buy_rate"`
		Sell string `json:"sell_rate"`
	}
	type JsonData_4 struct {
		Data JsonData_3 `json:"appraised_rates"`
	}
	var jsondata JsonData_4
	url := "https://data.gate.io/json_svr/query_push/?&type=push_main_rates&symbol=USDT_CNY"

	resp, err := GetBySS(url)
	if err != nil {
		beego.Debug("GetGateioUSDT ERROR")
		return
	}
	input, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return
	}
	//	input, err := ioutil.ReadAll(resp.Body)

	//	if err != nil {
	//		return 0.0
	//	}

	json.Unmarshal([]byte(input), &jsondata)
	buy, _ := strconv.ParseFloat(jsondata.Data.Buy, 64)
	sell, _ := strconv.ParseFloat(jsondata.Data.Sell, 64)
	rate = (buy + sell) / 2
	SaveRate(rate)
}

//func HandleCoincolaData(url string) float64 {
//	var sum float64

//	resp, count := GetByProxy(url)
//	if count > 5 {
//		beego.Debug("GetCoincolaData" + url)
//		return 0.0
//	}

//	doc, err := goquery.NewDocumentFromResponse(resp)
//	if err != nil {
//		//fmt.Println(err.Error())
//		return 0.0
//	}
//	doc.Find("tbody").Find("tr").EachWithBreak(func(i int, cs *goquery.Selection) bool {

//		cs.Find(".td-price").Each(func(j int, cs1 *goquery.Selection) {
//			d := cs1.Text()
//			str1 := strings.Replace(d, " ", "", -1)
//			str6 := strings.Replace(str1, "CNY", "", -1)
//			v2, err := strconv.ParseFloat(str6, 64)
//			if err != nil {
//				return
//			}
//			sum = sum + v2
//			//fmt.Println(sum)
//		})

//		if i >= 2 {
//			sum = sum / float64(i+1)
//			return false

//		}
//		return true
//	})
//	v, _ := strconv.ParseFloat(strconv.FormatFloat(sum, 'f', 2, 64), 64)
//	return v
//}

type BuySell struct {
	Sell float64
	Buy  float64
}

//func GetCoincolaData() {
//	symbol := [3]string{"BTC", "ETH", "LTC"}
//	start := int(time.Now().Unix())
//	for i := 0; i < len(symbol); i++ {
//		var buysell BuySell
//		url_buy := "https://www.coincola.com/buy/" + symbol[i] + "?country_code=CN"
//		buysell.Buy = HandleCoincolaData(url_buy)

//		url_sell := "https://www.coincola.com/sell/" + symbol[i] + "?country_code=CN"
//		buysell.Sell = HandleCoincolaData(url_sell)

//		time.Sleep(time.Second * 2)

//		SaveData(1, symbol[i], buysell)

//	}
//	end := int(time.Now().Unix())
//	models.SaveTest("Coincola", 1, start, end, end-start)
//}

func HandleOtcBtcData(url string) float64 {
	var sum float64
	var count float64
	resp, _ := GetByProxy(url)

	doc, err := goquery.NewDocumentFromResponse(resp)
	if err != nil {
		//fmt.Println(err.Error())
		return 0.0
	}
	doc.Find(".long-solution-list").Find(".list-content").EachWithBreak(func(i int, cs *goquery.Selection) bool {
		text := cs.Find(".price").Text()
		//		reg := regexp.MustCompile("\\d*\\,\\d*\\.\\d*|\\d*\\,\\d*|\\d*\\.\\d*|\\d*\\d*")
		//		fmt.Println(reg.FindAllString(text, -1))

		str1 := strings.Replace(text, " ", "", -1)
		str1 = strings.Replace(str1, ",", "", -1)
		str1 = strings.Replace(str1, "UnitPrice", "", -1)
		str1 = strings.Replace(str1, "CNY/BTC", "", -1)
		str1 = strings.Replace(str1, "CNY/ETH", "", -1)
		str1 = strings.Replace(str1, "CNY/LTC", "", -1)
		str1 = strings.Replace(str1, "单价", "", -1)
		str1 = strings.Replace(str1, "\n", "", -1)

		v1, err := strconv.ParseFloat(str1, 64)

		if err != nil {
			return false
		}
		textcount := cs.Find(".user-trust").Text()
		textcount0 := cs.Find(".user-trust").Find(".second-line").Text()
		//fmt.Println(textcount, textcount0)
		str2 := strings.Replace(textcount, textcount0, "", -1)
		str2 = strings.Replace(str2, " ", "", -1)
		str2 = strings.Replace(str2, "信用", "", -1)
		str2 = strings.Replace(str2, "交易", "", -1)
		str2 = strings.Replace(str2, "\n", "", -1)
		str2 = strings.Replace(str2, "Credibility", "", -1)
		str2 = strings.Replace(str2, "Trade", "", -1)
		v2, err2 := strconv.ParseFloat(str2, 64)
		//fmt.Println(str2)
		if err2 != nil {
			return false
		}
		//str2 := strings.Replace(textcount, " ", "", -1)
		//fmt.Println(str2)
		sum = sum + v1*v2
		count = count + v2
		if i >= 2 {
			sum = sum / count
			return false

		}
		return true

		//		cs.Find(".price").Each(func(j int, cs1 *goquery.Selection) {
		//			d := cs1.Text()
		//			fmt.Println(d)
		//			str1 := strings.Replace(d, " ", "", -1)
		//			str6 := strings.Replace(str1, "\n", "", -1)
		//			v2, err := strconv.ParseFloat(str6, 64)
		//			if err != nil {
		//				return
		//			}
		//			sum = sum + v2
		//			fmt.Println(sum)
		//		})

		//		if i >= 2 {
		//			sum = sum / float64(i+1)
		//			return falsego get github.com/astaxie/beego/logs

		//		}
		//		return true
	})
	//fmt.Println(sum)
	return MyRound(sum)
}

func GetOtcBtcData() {

	symbol := [2]string{"btc", "eth"}

	for i := 0; i < len(symbol); i++ {
		var buysell BuySell
		url_buy := "https://otcbtc.com/sell_offers?currency=" + symbol[i] + "&fiat_currency=cny&payment_type=all"
		buysell.Buy = HandleOtcBtcData(url_buy)

		url_sell := "https://otcbtc.com/buy_offers?currency=" + symbol[i] + "&fiat_currency=cny&payment_type=all"
		buysell.Sell = HandleOtcBtcData(url_sell)
		//fmt.Println(buysell.Buy, buysell.Sell, 2, symbol[i])
		time.Sleep(time.Second * 2)
		fmt.Println(buysell)
		SaveData(2, strings.ToUpper(symbol[i]), buysell)

	}

}

func GetGateiodata(symbol string) (buy float64, sell float64) {
	type JsonData struct {
		Buy  float64 `json:"buy"`
		Sell float64 `json:"sell"`
	}

	var jsondata JsonData

	url := "http://data.gate.io/api/1/ticker/" + strings.ToLower(symbol) + "_usdt"
	resp, err := GetBySS(url)

	if err != nil {

		return

	}
	defer resp.Body.Close()
	input, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	json.Unmarshal([]byte(input), &jsondata)
	buy = jsondata.Buy
	sell = jsondata.Sell
	return

}

func GetBiancedata(symbol string) (buy float64, sell float64) {
	type JsonData struct {
		Buy  string `json:"bidPrice"`
		Sell string `json:"askPrice"`
	}

	var jsondata JsonData

	url := "https://www.binance.com/api/v1/ticker/24hr?symbol=" + symbol + "USDT"
	resp, err := GetBySS(url)

	if err != nil {

		return

	}
	defer resp.Body.Close()
	input, err := ioutil.ReadAll(resp.Body)
	//	fmt.Println(string(input))
	if err != nil {
		return
	}

	json.Unmarshal([]byte(input), &jsondata)
	buy, _ = strconv.ParseFloat(jsondata.Buy, 64)
	sell, _ = strconv.ParseFloat(jsondata.Sell, 64)
	return
}

func GetHuobidata(symbol string) (buy float64, sell float64) {
	type JsonData_1 struct {
		Buy  [2]float64 `json:"bid"`
		Sell [2]float64 `json:"ask"`
	}

	type JsonData_2 struct {
		Data JsonData_1 `json:"tick"`
	}

	var jsondata JsonData_2

	url := "https://api.huobipro.com/market/detail/merged?symbol=" + strings.ToLower(symbol) + "usdt"

	resp, err := GetBySS(url)
	if err != nil {

		return

	}
	defer resp.Body.Close()
	input, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return
	}

	json.Unmarshal([]byte(input), &jsondata)
	buy = jsondata.Data.Buy[0]
	sell = jsondata.Data.Sell[0]
	return
}

func GetHuobiBianceGateio() {
	dataall := map[string]interface{}{
		"Code": 0,
		"Data": "",
		"Msg":  "",
	}
	data := map[string]interface{}{
		"Code": 0,
		"Data": "",
		"Msg":  "",
	}
	data0 := map[string]interface{}{}
	data0all := map[string]interface{}{}

	symbol := [3]string{"BTC", "ETH", "LTC"}
	rate := GetRateUSDT()
	over := models.GetOver()
	fmt.Println(over)
	for i := 0; i < len(symbol); i++ {
		var Data BuySell
		var Buy, Sell float64
		var count int

		Buy, Sell = GetGateiodata(symbol[i])
		//fmt.Println(Buy, Sell)
		if Buy > 0 && Sell > 0 {
			Data.Buy = Data.Buy + Buy
			Data.Sell = Data.Sell + Sell
			count++
		}
		Buy, Sell = GetBiancedata(symbol[i])
		//fmt.Println(Buy, Sell)
		if Buy > 0 && Sell > 0 {
			Data.Buy = Data.Buy + Buy
			Data.Sell = Data.Sell + Sell
			count++
		}
		Sell, Buy = GetHuobidata(symbol[i])
		//fmt.Println(Buy, Sell)

		if Buy > 0 && Sell > 0 {
			Data.Buy = Data.Buy + Buy
			Data.Sell = Data.Sell + Sell
			count++
		}
		//fmt.Println(Data, count)

		v1, _ := strconv.ParseFloat(strconv.FormatFloat((1+over)*Data.Buy*rate/float64(count), 'f', 2, 64), 64)

		Data.Buy = v1
		v2, _ := strconv.ParseFloat(strconv.FormatFloat((1-over)*Data.Sell*rate/float64(count), 'f', 2, 64), 64)
		Data.Sell = v2
		//fmt.Println(Data)
		var typebuysell TypeBuySell
		typebuysell.Buy = v1
		typebuysell.Sell = v2
		typebuysell.Type = 3
		data0[symbol[i]] = typebuysell
		data["Data"] = data0
		SetRedisBuyKey(symbol[i], data)

		data0all[symbol[i]] = typebuysell

		SaveData(3, symbol[i], Data)

	}
	dataall["Data"] = data0all
	SetRedisBuyKey("price", dataall)

}

func SaveData(Type int, Symbol string, buysell BuySell) {

	if buysell.Buy > 0 && buysell.Sell > 0 {
		o := orm.NewOrm()
		price := new(models.Price)
		price.Type = Type
		price.Symbol = Symbol
		price.Buy = buysell.Buy
		price.Sell = buysell.Sell
		price.Created = int(time.Now().Unix())

		o.Insert(price)
	} else {
		beego.Debug(Symbol+strconv.Itoa(Type)+"SaveData", "查看")
	}

}

func GetAllData() {

	//GetDataByCoin("ethereum")

	//GetCoincolaData()
	GetOtcBtcData()
	GetHuobiBianceGateio()

}

//设置定时器,定时刷新redis内容
func SetCoinriseDataForRedis() {

	key := "coinrise"

	//fmt.Println("new", key)
	symbols := utils.GetSymbolsByConf()

	data := map[string]interface{}{}

	for i := 0; i < len(symbols); i++ {
		data0 := map[string]interface{}{
			"price":     0.0,
			"rise":      0.0,
			"rise_mark": 0,
		}
		price := *new(TypeBuySell)
		price = GetDataFromMydql(symbols[i])
		var v float64
		if symbols[i] != "URMB" {
			v = MyRound((price.Buy + price.Sell) / 2)
		} else {
			v = MyRound((price.Buy + price.Sell) / 2)
		}

		data0["price"] = v
		data0["rise"], data0["rise_mark"] = GetRiseBy24H(symbols[i], v, price.Type)
		data[symbols[i]] = data0
	}

	//添加erc20代币价格,涨跌
	//	Uwncoinrise := GetErc20CoinRise("UWN")
	//	Uwncoinrise["price"] = MyRound(Uwncoinrise["price"].(float64) / priceURMB.Buy)
	//	data["UWN"] = Uwncoinrise

	utils.SetRedisBuyKey("v3"+key, data)

}

func SetPriceDataForRedis() {

	symbols := utils.GetSymbolsByConf()
	for _, v := range symbols {
		data := map[string]interface{}{
			"Code": 0,
			"Data": "",
			"Msg":  "",
		}
		data0 := map[string]interface{}{}
		price := GetDataFromMydql(v)

		data0[v] = price
		data["Data"] = data0
		utils.SetRedisBuyKey("v3"+v, data)
	}

}

func init() {
	//GetGateioUSDT()
	//GetHuobiBianceGateio()
	//GetHuoOutPrice()
	//	log := logs.NewLogger(10000) // 创建一个日志记录器，参数为缓冲区的大小
	//	// 设置配置文件
	//	jsonConfig := `{
	//	        "filename" : "log/test.log",
	//	        "maxlines" : 100000,
	//	        "maxsize"  : 10240
	//	    }`
	//	log.SetLogger(logs.AdapterFile, jsonConfig) // 设置日志记录方式：本地文件记录
	//	log.SetLevel(logs.LevelDebug)               // 设置日志写入缓冲区的等级
	//	log.EnableFuncCallDepth(true)               // 输出log时能显示输出文件名和行号（非必须）

	//	log.Emergency("Emergency")
	//	log.Alert("Alert")
	//	log.Critical("Critical")
	//	log.Error("Error")
	//	log.Warning("Warning")
	//	log.Notice("Notice")
	//	log.Informational("Informational")
	//	log.Debug("Debug")

	//	log.Flush() // 将日志从缓冲区读出，写入到文件
	//	log.Close()

	//	c1 := cron.New()
	//	spec1 := "0 0/3 * * * ?"
	//	c1.AddFunc(spec1, func() {
	//		beego.Debug("cron running: GetHuoOutPrice", 1)

	//		GetHuoOutPrice()

	//	})
	//	c1.Start()

	//	c2 := cron.New()

	//	spec2 := "0 1/4 * * * ?"
	//	c2.AddFunc(spec2, func() {
	//		beego.Debug("cron running: GetOtcBtcData", 2)

	//		GetOtcBtcData()

	//	})
	//	c2.Start()

	//	c3 := cron.New()
	//	spec3 := "*/30 * * * * ?"
	//	c3.AddFunc(spec3, func() {
	//		beego.Debug("cron running: GetHuobiBianceGateio", 3)
	//		//GetGateioUSDT()
	//		GetHuobiBianceGateio()

	//	})
	//c3.Start()

	c4 := cron.New()
	spec4 := "0/15 * * * * ?"
	c4.AddFunc(spec4, func() {
		go SetCoinriseDataForRedis()
		go SetPriceDataForRedis()
	})
	c4.Start()

}
